home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / rune.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  12KB  |  379 lines

  1. /*
  2.  * static char *rcsid_rune_c =
  3.  *   "$Id: rune.c,v 1.14 1996/07/24 07:40:38 master Exp master $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #include <global.h>
  30. #ifndef __CEXTRACT__
  31. #include <sproto.h>
  32. #endif
  33. #include <spells.h>
  34. #include <errno.h>
  35. #ifdef sequent
  36. /* stoopid sequent includes don't do this like they should */
  37. extern char * sys_errlist[];
  38. extern int sys_nerr;
  39. #endif
  40.  
  41. extern object *objects;
  42.  
  43. /*  peterm:  
  44.     write_rune:
  45.     op:  rune writer
  46.     dir:  orientation of rune, direction rune's contained spell will
  47.         be cast in, if applicable
  48.     inspell:  the spell index of the spell in the rune (if any)
  49.     level:  level of casting of the rune
  50.     runename:  name of the rune or message displayed by the rune for
  51.         a rune of marking 
  52.  
  53. */
  54.  
  55. int write_rune(object *op,int dir,int inspell,int level,char *runename) { 
  56.     object *tmp;
  57.     archetype *at=NULL;
  58.     char *buf=(char *)malloc(sizeof(char) * 40);
  59.     
  60.     int nx,ny;
  61.  
  62.       if(!dir) {
  63.     dir=1;
  64.     } 
  65.  
  66.     nx=op->x+freearr_x[dir];
  67.     ny=op->y+freearr_y[dir];
  68.     if(blocked(op->map,nx,ny)) {
  69.     new_draw_info(NDI_UNIQUE, 0,op,"Can't make a rune there!");
  70.     return 0;
  71.     }
  72.     for(tmp=get_map_ob(op->map,nx,ny);tmp!=NULL;tmp=tmp->above)
  73.     if(tmp->type==RUNE) break;
  74.     if(tmp){
  75. #if 0
  76.     new_draw_info(NDI_UNIQUE, 0,op,"You only succeed in strengthening that rune.");
  77.     tmp->stats.hp++;
  78.     return 1;
  79. #endif
  80.       new_draw_info(NDI_UNIQUE, 0,op,"You can't write a rune there.");
  81.       return 0;
  82.     }
  83.     if(inspell) {  /* can't have runes of small fireball!!!  */
  84.     if(inspell==-1) { new_draw_info(NDI_UNIQUE, 0,op,"You can't make a rune containing");
  85.               new_draw_info(NDI_UNIQUE, 0,op,"a spell you don't know.  (idiot!)");
  86.               return 0;
  87.     }
  88.     at=find_archetype(runename);
  89.  
  90.     /* What it compares to should probably be expanded.  But basically,
  91.      * creating a rune of sword should not be allowed. */
  92.     if (at->clone.type!=RUNE) {
  93.          new_draw_info_format(NDI_UNIQUE, 0, op,
  94.         "You can't make a rune of %s", runename);
  95.         return 0;
  96.     }
  97.         /* next it attempts to look up a rune_archetype for this spell
  98.         by doing some string manipulations */
  99.     if(!at) {
  100.         char buf[MAX_BUF];
  101.         char insp[MAX_BUF];
  102.         int i;
  103.         strcpy(insp,spells[inspell].name);
  104.         for(i=0;i<strlen(insp);i++)
  105.             if(insp[i]==' ') insp[i]='_';
  106.         sprintf(buf,"%s%s","rune_",insp);
  107.         at=find_archetype(buf);
  108.     }
  109.         
  110.     if(!at) tmp=get_archetype("generic_rune");
  111.     else
  112.     tmp=arch_to_object(at);
  113.  
  114.     tmp->stats.sp=inspell; /* the spell it contains */
  115.  
  116.     sprintf(buf,"You set off a rune of %s",spells[inspell].name);
  117.     tmp->msg=add_string(buf); 
  118.     at=NULL;
  119.  
  120.   /* the only circumstance in which we remove buf, otherwise we need it.*/
  121.     } else if (level!=-2 && (at=find_archetype(runename))!=NULL) free(buf);
  122.         /*  the at=find_archetye(runename) was neccessary because
  123.         tmp=get_archetype returns a singulirity, not a null,
  124.         when it cannot find the archetype.  */
  125.             /* note: if some smartass
  126.             cast rune of marking, and gives the exact name
  127.             of a powerful rune, it won't do him any good,
  128.             because a rune of marking will have level 0
  129.             and will thus never detonate. */
  130.       else { /* it's a rune of marking */
  131.     level=0;
  132.     tmp=get_archetype("rune_mark"); /* this is a rune of marking */
  133.     at=NULL;
  134.     tmp->msg = add_string((runename?runename:"There is no message"));
  135.       }
  136.     if(at) tmp=get_archetype(runename);
  137.     tmp->stats.Cha = op->level/2;  /* the invisibility parameter */
  138.     tmp->x=nx;
  139.     tmp->y=ny;
  140.     tmp->map = op->map;
  141.     tmp->direction=dir;  /* where any spell will go upon detonation */
  142.     tmp->level=SK_level(op);  /* what level to cast the spell at */
  143.     set_owner(tmp,op);
  144.     insert_ob_in_map(tmp,op->map);
  145.     return 1;
  146.  
  147. }
  148.  
  149.  
  150. /*  move_rune:  peterm
  151.   comments on runes:
  152.     rune->level        :        level at which rune will cast its spell.
  153.     rune->hp        :        number of detonations before rune goes away
  154.     rune->sp        :        index of the spell the rune casts
  155.     rune->msg        :        message the rune displays when it goes off
  156.     rune->direction :        direction it will cast a spell in
  157.     rune->dam        :        damage the rune will do if it doesn't cast spells
  158.     rune->attacktype:        type of damage it does, if not casting spells
  159.     rune->slaying   :       string description of the spell in the rune
  160.  
  161. */
  162.  
  163. void move_rune(object *op) {
  164.     object *tmp;
  165.     int det=0;
  166.     if(!op->level) {return;}  /* runes of level zero cannot detonate. */
  167.     for(tmp=op->above;tmp;tmp=tmp->above)
  168.     if(!QUERY_FLAG(tmp,FLAG_FLYING)&&QUERY_FLAG(tmp,FLAG_ALIVE))
  169.         {det|=1;break;}
  170.     if(det) spring_trap(op,tmp);
  171.  
  172.     det=op->invisible;
  173.     if(!(RANDOM()%(MAX(1,(op->stats.Cha)))))
  174.     {
  175.     op->invisible=0;
  176.     op->speed_left-=1;
  177.     }
  178.     else
  179.     op->invisible=1;
  180.     if(op->invisible!=det)
  181.     update_object(op);
  182. }
  183.  
  184.  
  185. /*  peterm: rune_attack
  186.  
  187.   function handles those runes which detonate but do not cast spells.  */
  188.  
  189.  
  190. void rune_attack(object *op,object *victim)
  191. {
  192.   if(victim)  hit_player(victim,op->stats.dam,op,op->attacktype);
  193.    else  hit_map(op,0,op->attacktype);
  194. }
  195.  
  196. /*  This function generalizes attacks by runes/traps.  This ought to make
  197.     it possible for runes to attack from the inventory, 
  198.     it'll spring the trap on the victim.  */
  199.    
  200. void spring_trap(object *trap,object *victim)
  201. {  int spell_in_rune;
  202.    object *env;
  203.   trap->stats.hp--;  /*decrement detcount */
  204.   /*  get the spell number from the name in the slaying field, and set
  205.       that as the spell to be cast. */
  206.   if((spell_in_rune=look_up_spell_by_name(NULL,trap->slaying))!=-1) trap->stats.sp=spell_in_rune;
  207.   if(victim) if(victim->type==PLAYER) new_draw_info(NDI_UNIQUE, 0,victim,trap->msg);
  208.   if(!trap->stats.sp) rune_attack(trap,victim); 
  209.   else {
  210.     remove_ob(trap);
  211.     trap->x=victim->x;trap->y=victim->y;
  212.     insert_ob_in_map(trap,victim->map);
  213.     cast_spell(trap,trap,trap->direction,trap->stats.sp,1,spellNormal,NULL);
  214.   }
  215.   for(env=trap;env!=NULL&&env->env!=NULL;env=env->env);
  216.   trap_show(trap,env);  
  217.   if(!trap->stats.hp) {
  218.     trap->type=98;  /* make the trap impotent */
  219.     trap->stats.food=20;  /* make it stick around until it's spells are gone */
  220.     SET_FLAG(trap,FLAG_IS_USED_UP);
  221.   }
  222. }
  223.  
  224. /*  dispel_rune:  by peterm  
  225.     dispels the target rune, depending on the level of the actor
  226. and the level of the rune  risk flag, if true, means that there is
  227. a chance that the trap/rune will detonate */
  228.  
  229. int dispel_rune(object *op,int dir,int risk)
  230. {
  231.   object *tmp,*tmp2;
  232.   int searchflag = 1;
  233.    if(out_of_map(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) return 0;
  234.    for(tmp=get_map_ob(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir]);
  235.         tmp!=NULL;  tmp=tmp->above) 
  236.     {
  237.       if(tmp->type==RUNE) break;
  238.         /* now search tmp's inventory for traps */
  239.       for(tmp2=tmp->inv;tmp2!=NULL;tmp2=tmp2->below) {
  240.         if(tmp2->type==RUNE) { 
  241.             tmp=tmp2;
  242.             searchflag=0;
  243.             break;
  244.         }
  245.       }
  246.       if(!searchflag) break;
  247.     }
  248.         
  249.   if(tmp==NULL)               /*no rune there. */
  250.     {
  251.     new_draw_info(NDI_UNIQUE, 0,op,"There's no trap there!");
  252.     return 0;
  253.     }
  254.   trap_disarm(op,tmp,risk);
  255.   return 1;
  256.     
  257. }
  258.  
  259. int trap_see(object *op,object *trap) {
  260.   char buf[MAX_BUF];
  261.   int chance;
  262. #ifndef ALLOW_SKILLS 
  263.   int trapworth=0;  
  264. #endif
  265.  
  266.   chance = RANDOM()%100;
  267.   
  268.   /*  decide if we see the rune or not */
  269.   if((trap->stats.Cha==1) || (chance >
  270.         MIN(95,MAX(5,((int)((float) (op->map->difficulty 
  271.     + trap->level + trap->stats.Cha-op->level)/10.0 * 50.0))))))
  272.   {
  273.       sprintf(buf,"You spot a %s!",trap->name);
  274.       new_draw_info(NDI_UNIQUE, 0,op,buf);
  275.  
  276. #ifndef ALLOW_SKILLS /* this stuff is handled by find_trap skill code -b.t. */ 
  277.       trapworth = trap->stats.Cha * trap->level;
  278.       if(trap->stats.Cha>1) add_exp(op,trapworth);  /* finding a trap awards exp */
  279.       trap->stats.Cha=1;  /* unhide the rune/trap */
  280. #endif
  281.       return 1;
  282.   }
  283.   return 0;
  284. }
  285.  
  286. int trap_show(object *trap, object *where) {
  287.   object *tmp2;
  288.  
  289.   if(where==NULL) return 0;
  290.   tmp2=get_archetype("runedet");
  291.   tmp2->face=&new_faces[trap->arch->faces[0]];
  292.   tmp2->x=where->x;tmp2->y=where->y;tmp2->map=where->map;
  293.   insert_ob_in_map(tmp2,where->map);
  294.   return 1;
  295.  
  296. }
  297.  
  298. #ifndef sqr
  299. #define sqr(x) ((x)*(x))
  300. #endif
  301. int trap_disarm(object *disarmer, object *trap, int risk) {
  302.  
  303.   int trapworth;  /* need to compute the experience worth of the trap
  304.                      before we kill it */
  305.   /* this formula awards a more reasonable amount of exp */
  306.   trapworth =  MAX(1,trap->level)  * disarmer->map->difficulty *
  307.     sqr(MAX(trap->stats.dam,spells[trap->stats.sp].sp)) /
  308.     disarmer->level;
  309.  
  310.     if(!(RANDOM()%(MAX(2,
  311.                MIN(20,trap->level-disarmer->level 
  312.                +5 - disarmer->stats.Dex/2)))))
  313.         {
  314.             new_draw_info(NDI_UNIQUE, 0,disarmer,"You successfuly disarm it!");
  315.             remove_ob(trap);
  316.             free_object(trap);
  317. #ifdef ALLOW_SKILLS 
  318.             return trapworth;    
  319. #else
  320.         if(!trap->owner) add_exp(disarmer,trapworth);
  321.             else if(trap->owner && trap->owner->type!=PLAYER && risk)
  322.           add_exp(disarmer,trapworth);
  323.         return 1;
  324. #endif
  325.         }
  326.     else
  327.         {
  328.             new_draw_info(NDI_UNIQUE, 0,disarmer,"You fail to disarm the trap.");
  329.         if(! (RANDOM()% (MAX(2,disarmer->level-trap->level 
  330.                  + disarmer->stats.Dex/2-6)))
  331.            &&risk) {
  332.         new_draw_info(NDI_UNIQUE, 0,disarmer,"In fact, you set it off!");
  333.         spring_trap(trap,disarmer);
  334.         }
  335.             return 0;
  336.         }
  337. }
  338.  
  339.  
  340. /*  traps need to be adjusted for the difficulty of the map.  The
  341. default traps are too strong for wimpy level 1 players, and 
  342. unthreatening to anyone of high level */
  343.  
  344. void trap_adjust(object *trap, int difficulty)
  345. { int i;
  346.   /*  first we set the sp value of the trap if it has a spell in it. */
  347.   if(trap->slaying) {
  348.     trap->stats.sp = look_up_spell_name(trap->slaying);
  349.     trap->stats.dam = 0;
  350.   }
  351.   if(trap->stats.sp ==-1) trap->stats.sp = 0;
  352.  
  353.   /* now we set the trap level to match the difficulty of the level */
  354.   /* the formula below will give a level from 1 to (2*difficulty) with */
  355.   /* a peak probability at difficulty */
  356.  
  357.   trap->level = MAX(1,RANDOM()%difficulty + RANDOM()%difficulty);
  358.  
  359.   /* set the hiddenness of the trap, similar formula to above */
  360.   trap->stats.Cha = RANDOM()%20 + RANDOM()%difficulty + RANDOM()%difficulty;
  361.  
  362.   /* set the damage of the trap if it's not a spellcasting trap 
  363.     we get 0-4 pts of damage per level of difficulty of the map in
  364.         the trap*/
  365.  
  366.   if(trap->stats.sp == 0) {
  367.     trap->stats.dam = 0;
  368.     for(i=0;i<difficulty;i++) trap->stats.dam+=RANDOM()%5;
  369.   }
  370.     
  371.  
  372.   /*  the poison trap special case */
  373.   if(trap->attacktype & AT_POISON) trap->stats.dam = MAX(1,RANDOM()%difficulty);  
  374.  
  375.   /*  so we get an appropriate amnt of exp for AT_DEATH traps */
  376.   if(trap->attacktype & AT_DEATH) trap->stats.dam = 127;
  377.  
  378. }
  379.